﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Data;
using System.Net.Mail;
using System.IO;
using System.Data.SqlClient;

namespace ASBCC.MailService
{
    public class NetMailUtility
    {
        private const string LOG_FORMAT = "------------------------------------------------------------------------------------------------------------\r\n"
            + "MAILID:\t [{0}]\r\n"
            + "SEND DATE:\t [{1}]\r\n"
            + "STATUS:\t\t [{2}] \r\n"
            + "DESCRIPTION:\t [{3}]\r\n------------------------------------------------------------------------------------------------------------\r\n";
        private const string MAIL_STATUS_WAITING = "WAT";
        private const string MAIL_STATUS_SUCCEED = "OVR";
        private const string MAIL_STATUS_FAILED = "FAL";
        private const string MAIL_STATUS_ONGOING = "ING";
        private const string SQL_GET_MAILS = "SELECT TOP {0} * FROM MAILPOOL WHERE STATUS = '{1}' order by CreateDateTime asc ; UPDATE MAILPOOL SET STATUS = '{2}' WHERE MAIL_SN  IN (SELECT TOP {0} MAIL_SN FROM MAILPOOL WHERE STATUS = '{1}');";
        private const string SQL_UPDATE_MAIL_STATUS = "UPDATE MAILPOOL SET STATUS = '{1}', SendDateTime = getdate() WHERE MAIL_SN = '{0}'";
        private const string SQL_GET_MAIL_ATTACHMENTS = "SELECT * FROM MAILATTACHMENT WHERE MAILID = '{0}' ORDER BY SORT ";
        private const string DONOT_NEED_FIX_PREFIX = "<HTML>";
        private const string FIXED_MAIL_BODY = @"<html><head>
<meta http-equiv='Content-Language' content='zh-cn'/>
<meta http-equiv='Content-Type' content='text/html; charset=gb2312'/>
<style type='text/css'>
<!--
.body {
    font-family: Verdana, Arial, Helvetica, sans-serif;
    font-size: 10px;
}
-->
</style>
</head>
<body>

#BODY#

</body>
</html>
";
        private const string FIXED_MAIL_BODY_NO_REPLY = @"<html><head>
<meta http-equiv='Content-Language' content='zh-cn'/>
<meta http-equiv='Content-Type' content='text/html; charset=gb2312'/>
<style type='text/css'>
<!--
.body {
    font-family: Verdana, Arial, Helvetica, sans-serif;
    font-size: 10px;
}
-->
</style>
</head>
<body>

#BODY#

</body>
</html>
";

        private int _mailAmount;
        private SqlDataAdapter adap;
        private string sql = "";
        private string _sender = "";
        private string _displayName = "";
        private bool _liveMode = false;
        private string _testRecipients = "";
        private string _logFile = "";
        private bool _saveSucceedLog = false;
        private bool _saveFailedLog = true;

        private string _FromConfig = "";
        private string _DisplayConfig = "";

        private string _From = "";
        private bool _EnableSsl = false;

        private string _smtphost = "";
        private string _username = "";
        private string _password = "";


        public NetMailUtility(string connstr, string smtphost, string username, string password, int mailAmount, bool liveMode, string testRecipients,
            string sender, string displayName, bool enableSsl, string logFile, bool saveSucceedLog, bool saveFailedLog)
        {
            adap = new SqlDataAdapter(sql, connstr);

            if (mailAmount > 0)
            {
                _mailAmount = mailAmount;
            }
            else
            {
                _mailAmount = 100;
            }
            _sender = sender;
            _displayName = displayName;
            _liveMode = liveMode;
            _testRecipients = testRecipients;
            _logFile = logFile;
            _saveSucceedLog = saveSucceedLog;
            _saveFailedLog = saveFailedLog;

            _From = sender;

            _FromConfig = sender;
            _DisplayConfig = displayName;

            _EnableSsl = enableSsl;

            _smtphost = smtphost;
            _username = username;
            _password = password;

        }

        public NetMailUtility()
        {
        }

        public void SendMails()
        {
            string status = "";
            string mailTo = "";
            string cc = "";
            string bcc = "";
            string testSubjectPrefix = "";
            bool hasFrom = false;

            DataTable dtMails = GetData(string.Format(SQL_GET_MAILS, _mailAmount.ToString(), MAIL_STATUS_WAITING, MAIL_STATUS_ONGOING));
            foreach (DataRow dr in dtMails.Rows)
            {
                if (!_liveMode)
                {
                    mailTo = _testRecipients;
                    testSubjectPrefix = "[TEST MAIL]";
                }
                else
                {
                    testSubjectPrefix = "";
                    mailTo = dr["RECEIPIENTS"].ToString();
                    try
                    {
                        cc = dr["CC"].ToString();
                    }
                    catch
                    { }
                    try
                    {
                        bcc = dr["BCC"].ToString();
                    }
                    catch
                    { }

                }
                if ((mailTo.Trim() != "" || cc.Trim() != "" || bcc.Trim() != "") && (dr["SUBJECT"].ToString().Trim() != "") && (dr["BODY"].ToString().Trim() != ""))
                {
                    try
                    {
                        Send(_smtphost, _username, _password, _sender, _From, _displayName,
                            mailTo,
                            testSubjectPrefix + dr["SUBJECT"].ToString(),
                            FixMailBody(dr["BODY"].ToString(), hasFrom),
                            dr["body_format"].ToString() == "HTML",
                            bcc,
                            cc,
                            dr["PRIOR"].ToString(),
                            _EnableSsl, dr["MAIL_SN"].ToString());
                        status = MAIL_STATUS_SUCCEED;
                        try
                        {
                            if (_saveSucceedLog)
                            {
                                SaveLog(dr["MAIL_SN"].ToString(), "SUCCEED", "SUCCEED");
                            }
                        }
                        catch
                        {
                        }

                    }
                    catch (Exception ee)
                    {
                        status = MAIL_STATUS_FAILED;
                        try
                        {
                            if (_saveFailedLog)
                            {
                                SaveLog(dr["MAIL_SN"].ToString(), "FAILED", ee.Message);
                            }
                        }
                        catch
                        { }
                    }
                }
                else
                {
                    status = MAIL_STATUS_FAILED;
                    string logx = "";
                    if (mailTo.Trim() == "")
                    {
                        logx += "Recipients,";
                    }

                    if (dr["SUBJECT"].ToString().Trim() == "")
                    {
                        logx += "Subject,";
                    }

                    if (dr["BODY"].ToString().Trim() == "")
                    {
                        logx += "Body,";
                    }


                    SaveLog(dr["MAIL_SN"].ToString(), "FAILED", logx.Trim(',') + " is empty");
                }
                GetData(string.Format(SQL_UPDATE_MAIL_STATUS, dr["MAIL_SN"].ToString(), status));
            }


        }
        private void SaveLog(string mailSn, string status, string description)
        {
            string content = string.Format(LOG_FORMAT, mailSn, DateTime.Now, status, description);
            File.AppendAllText(_logFile, content, Encoding.UTF8);
        }

        public void Send(string smtphost, string username, string password, string sender, string from, string displayName, string recipients, string subject, string body, bool ishtmlBody, string bcc, string cc, string priority, bool enableSsl, string mailid)
        {
            System.Net.Mail.SmtpClient client = new SmtpClient(smtphost);
            client.Credentials = new System.Net.NetworkCredential(username, password);
            MailMessage message = new MailMessage();

            message.From = new MailAddress(from, displayName);
            message.Sender = new MailAddress(sender);

            foreach (string strTo in recipients.Split(',', ';'))
            {
                if (strTo.Trim().Length != 0)  //ignore empty mail address
                {
                    message.To.Add(new MailAddress(strTo.Trim()));
                }
            }

            foreach (string strTo in bcc.Split(',', ';'))
            {
                if (strTo.Trim().Length != 0)  //ignore empty mail address
                {
                    message.Bcc.Add(new MailAddress(strTo.Trim()));
                }
            }

            foreach (string strTo in cc.Split(',', ';'))
            {
                if (strTo.Trim().Length != 0)  //ignore empty mail address
                {
                    message.CC.Add(new MailAddress(strTo.Trim()));
                }
            }

            // 发送附件
            DataTable dtMailAttachments = GetData(string.Format(SQL_GET_MAIL_ATTACHMENTS, mailid));
            foreach (DataRow dr in dtMailAttachments.Rows)
            {
                try
                {
                    if (dr["FullPathName"].ToString().Trim() != "")
                    {
                        string attachmentpath = dr["FullPathName"].ToString();
                        Attachment att = new Attachment(attachmentpath);
                        //modify attachment information
                        System.Net.Mime.ContentDisposition disposition = att.ContentDisposition;
                        disposition.CreationDate = System.IO.File.GetCreationTime(attachmentpath);
                        disposition.ModificationDate = System.IO.File.GetLastWriteTime(attachmentpath);
                        disposition.ReadDate = System.IO.File.GetLastAccessTime(attachmentpath);
                        disposition.FileName = dr["FileName"].ToString();
                        //add attachent
                        message.Attachments.Add(att);
                    }
                }
                catch
                { }
            }

            switch (priority.ToLower())
            {
                case "normal":
                    message.Priority = MailPriority.Normal;
                    break;
                case "high":
                    message.Priority = MailPriority.High;
                    break;
                case "low":
                    message.Priority = MailPriority.Low;
                    break;
            }

            message.Subject = subject;
            message.SubjectEncoding = System.Text.Encoding.UTF8;

            message.Body = body;
            message.BodyEncoding = System.Text.Encoding.UTF8;

            message.IsBodyHtml = ishtmlBody;

            client.EnableSsl = enableSsl;

            client.Send(message);
            message.Dispose();
        }

        public string FixMailBody(string body, bool hasFrom)
        {
            string result = "";
            string prefix = "";
            if (body.Length > DONOT_NEED_FIX_PREFIX.Length)
            {
                prefix = body.TrimStart().Substring(0, DONOT_NEED_FIX_PREFIX.Length);
            }

            if (prefix.ToUpper() == DONOT_NEED_FIX_PREFIX.ToUpper())
            {
                result = body;
            }
            else
            {
                result = FIXED_MAIL_BODY.Replace("#BODY#", body);
            }

            return result;
        }

        private DataTable GetData(string sql)
        {
            DataTable dt = new DataTable();
            try
            {
                adap.SelectCommand.CommandText = sql;
                adap.Fill(dt);
            }
            catch (Exception ex)
            {
                throw;
            }
            return dt;
        }
    }
}
